package com.rd.sys.service.analysis.project.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import baseproj.common.exception.BaseServiceException;

import com.rd.sys.common.base.CommonConstants;
import com.rd.sys.common.utils.JacksonMapper;
import com.rd.sys.common.utils.cache.AnalysisCache;
import com.rd.sys.common.utils.client.AnalysisPathUtils;
import com.rd.sys.common.utils.file.FileLockUtils;
import com.rd.sys.common.utils.file.HandlerCaller;
import com.rd.sys.dto.client.store.Project;
import com.rd.sys.dto.commmon.enums.SyncEnum;
import com.rd.sys.service.analysis.project.ProjectService;
import com.rd.sys.service.analysis.scheme.SchemeService;

@Service
@Transactional(rollbackFor = {Exception.class})
public class ProjectServiceImpl implements ProjectService {
    protected static final Logger logger = LoggerFactory.getLogger(ProjectServiceImpl.class);

    @Autowired
    private SchemeService schemeService;

    /**
     * 查询项目描述详情
     * 
     * @param userCode
     * @param projectName
     * @return
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<Project> queryProjectList(String userCode, String projectName) {
        try {
            List<Project> rtnProjectList = new LinkedList<Project>();

            /** 从缓存中读取 ,没有就从文件中读取 */
            List<Project> projectList = AnalysisCache.ProjectCache.get(userCode);

            if (projectList == null) {
                return null;
            }

            /** 按查询关键字过滤,并进一步查询包含的方案详情 */
            Iterator<Project> iterator = projectList.iterator();
            while (iterator.hasNext()) {
                Project project = iterator.next();
                if (StringUtils.isNotBlank(projectName)) { // 当需要查询过滤,并且不满足条件时,直接移除
                    if (!project.getProjectName().contains(projectName)) {
                        continue;
                    }
                }
                rtnProjectList.add(project);
                project.setSchemeList(schemeService.querySchemeList(userCode, project.getProjectCode())); // 查询包含的方案详情
            }

            return rtnProjectList;

        } catch (BaseServiceException be) {
            throw be;
        } catch (Exception ex) {
            logger.error("query project list error", ex);
            throw new RuntimeException(ex);
        }
    }

    /**
     * 从项目描述文件中读取项目信息
     * 
     * @param userCode
     * @return
     * @throws Exception
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<Project> readProjectList(String userCode) throws Exception {
        List<Project> projectList = null;

        /** 从项目描述文件中读取出来 */
        File file = new File(AnalysisPathUtils.findProjectFileName(userCode));
        if (!file.exists()) {
            file.createNewFile(); // 对文件为空时做个保护
            projectList = new LinkedList<Project>();
        } else {
            byte[] projectBytes = FileUtils.readFileToByteArray(file);
            if (projectBytes.length > 0) {
                String projectJson = new String(projectBytes, CommonConstants.SysParamConstants.SYS_CHARSET);
                projectList = (List<Project>) JacksonMapper.json2List(projectJson, Project.class);
            } else {
                projectList = new LinkedList<Project>();
            }
        }

        return projectList;
    }

    /**
     * 同步项目信息
     * 
     * @param userno
     * @param userCode
     * @param project
     *            待新增的项目
     * @param opercode
     *            操作代码
     * @throws Exception
     */
    public void syncProject(Integer userno, String userCode, Project project, String opercode) throws Exception {
        try {
            /** 再执行实际同步信息 */
            File lockFile = new File(AnalysisPathUtils.findProjectFileName(userCode)
                    + CommonConstants.AnalysisConstats.SYNC_FILE_LOCK_SUFFIX);
            File srcFile = new File(AnalysisPathUtils.findProjectFileName(userCode));
            File projectPath = new File(AnalysisPathUtils.findProjectPath(userCode, project.getProjectCode()));

            // 定义回调执行流程
            Object[] array = new Object[] {userCode, project, srcFile, projectPath, opercode};
            HandlerCaller caller = new HandlerCaller(array) {
                @Override
                public void execute(FileChannel lockChannel) throws Exception {
                    /** 1.分解各个字段 */
                    Object[] array = (Object[]) this.object;
                    String key = (String) array[0];
                    Project project = (Project) array[1];
                    File srcFile = (File) array[2];
                    File projectPath = (File) array[3];
                    String opercode = (String) array[4];

                    /** 2.读取当前项目信息,根据项目编码判断是否存在 */
                    List<Project> projectList = AnalysisCache.ProjectCache.get(key);
                    Iterator<Project> iterator = projectList.iterator();
                    Project dto = null;
                    boolean isHave = false;
                    while (iterator.hasNext()) {
                        dto = iterator.next();
                        if (dto.getProjectCode().equals(project.getProjectCode())) {
                            isHave = true;
                            break;
                        }
                    }

                    if (SyncEnum.Opercode.DELETE.getCode().equals(opercode)) {
                        if (isHave) { // 做个保护,存在则删除,不存在也正常
                            projectList.remove(dto);
                        }
                    } else if (SyncEnum.Opercode.ADD.getCode().equals(opercode)
                            || SyncEnum.Opercode.EDIT.getCode().equals(opercode)) {
                        if (isHave) {
                            dto.setProjectDesc(project.getProjectDesc()); // 只更新项目描述
                        } else {
                            projectList.add(project);
                        }
                    }

                    /** 3.同步的项目信息转换 */
                    String newProjectJson = JacksonMapper.list2Json(projectList);
                    ByteBuffer buffer = ByteBuffer.wrap(newProjectJson
                            .getBytes(CommonConstants.SysParamConstants.SYS_CHARSET));

                    /** 4.写入信息并更新缓存 */
                    FileChannel srcChannel = null;
                    try {
                        srcChannel = new FileOutputStream(srcFile).getChannel();
                        srcChannel.write(buffer); // 实际写入描述文件

                        if (!projectPath.exists()) { // 创建项目目录
                            projectPath.mkdir();
                        }

                        // 处理项目目录
                        if (SyncEnum.Opercode.DELETE.getCode().equals(opercode)) {
                            FileUtils.deleteDirectory(projectPath); // 删除项目目录
                        } else if (SyncEnum.Opercode.ADD.getCode().equals(opercode)) {
                            if (!projectPath.exists()) { // 创建项目目录
                                projectPath.mkdir();
                            }
                        }

                        AnalysisCache.ProjectCache.put(key, projectList); // 更新缓存
                    } catch (Exception ex) {
                        throw ex;
                    } finally {
                        if (srcChannel != null) {
                            try {
                                srcChannel.close();
                            } catch (Exception ex) {
                                logger.error("", ex);
                            }
                        }
                    }

                }
            };

            FileLockUtils.handlerByLockFile(lockFile, caller); // 调用文件锁定方式操作
        } catch (Exception ex) {
            logger.error("", ex);
            throw new RuntimeException(ex);
        }
    }

}
